//
// Created by mio on 25-4-10.
//

#ifndef BUFFERREADER_H
#define BUFFERREADER_H

#include <vector>
#include <string>
#include <cstdint>

uint32_t ReadUint32BE(char* data);
uint32_t ReadUint32LE(char* data);
uint32_t ReadUint24BE(char* data);
uint32_t ReadUint24LE(char* data);
uint16_t ReadUint16BE(char* data);
uint16_t ReadUint16LE(char* data);

class BufferReader
{
public:
    BufferReader(uint32_t initial_size = 2048);
    virtual ~BufferReader();
    /**
     * @brief 获取当前缓冲区中可读数据的字节数。
     * @return 可读字节数。
     */
    inline uint32_t ReadableBytes() const { return  writer_index_ - reader_index_; }
    /**
     * @brief 获取当前缓冲区中剩余可写空间的字节数（在当前分配大小内）。
     * @return 可写字节数。
     */
    inline uint32_t WritableBytes() const { return buffer_.size() - writer_index_; }
    /**
     * @brief 获取指向可读数据起始位置的指针（只读）。
     * @return 指向可读数据开头的 char 指针。用于查看数据，不移动读索引。
     */
    char* Peek() { return Begin() + reader_index_; }
    const char* Peek() const { return Begin() + reader_index_; } // const 版本
    /**
     * @brief 重置缓冲区，丢弃所有数据，将读写索引归零。
     * 使整个缓冲区变为空闲可写状态。
     */
    void RetriveveAll()
    {
        writer_index_ = 0; reader_index_ = 0;
    }
    /**
     * @brief 从可读区域“取走”（消耗）指定长度的数据。
     * 实际上只是移动读索引 reader_index_。
     * @param len 要取走的数据长度（字节）。
     */
    void Retrieve(size_t len)
    {
        // 确保要取走的长度不超过当前可读的长度
        if (len < ReadableBytes())
        {
            reader_index_ += len; // 向前移动读索引
            // 优化：如果读取后，读写索引重合，说明所有数据都被读取了
            // 可以直接重置索引，以便下次写入能从头开始，避免空间浪费
            if (reader_index_ == writer_index_)
            {
                RetriveveAll();
            }
        }
        else // 如果要取走的长度大于等于可读长度，则相当于取走所有数据
        {
            RetriveveAll();
        }
    }
    /**
     * @brief 从指定的文件描述符（通常是 socket）读取数据到缓冲区中。
     * 会根据需要自动扩展缓冲区的大小（有最大限制）。
     * @param fd 要读取数据的文件描述符。
     * @return 成功读取的字节数；0 表示对方关闭连接；-1 表示发生错误（errno 会被设置）。
     */
    int Read(int fd);
    /**
     * @brief 读取缓冲区中所有可读的数据，并将其存入提供的 std::string 中。
     * 读取后会清空缓冲区（重置读写索引）。
     * @param data 用于接收数据的 std::string 引用。
     * @return 成功读取并存入 string 的字节数。
     */
    uint32_t ReadAll(std::string& data);
    uint32_t Size() const { return buffer_.size(); }

private:
    char* Begin() { return &*buffer_.begin(); }
    const char* Begin() const { return &*buffer_.begin(); }
    char* BeginWrite() { return Begin() + writer_index_; }
    const char* BeginWrite() const { return Begin() + writer_index_; }

private:
    std::vector<char> buffer_;
    size_t reader_index_ = 0;  // 读索引：标记可读数据的起始位置
    size_t writer_index_ = 0;  // 写索引：标记可读数据的结束位置 / 可写数据的起始位置
    // 每次尝试从 fd 读取的最大字节数
    static const uint32_t MAX_BYTES_PER_READ = 4096;
    // 缓冲区允许增长到的最大容量，防止内存无限增长
    static const uint32_t MAX_BUFFER_SIZE = 1024 * 100000;
};



#endif //BUFFERREADER_H
